import requests
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import threading
from requests.exceptions import Timeout
# 全局配置
CONCURRENCY = 256  # 并发协程数
RETRY_TIMES = 3    # 单任务重试次数
TIMEOUT = 100       # 请求超时时间
url = 'http://192.168.110.46:8001/v1/chat/completions'
#url = 'https://cloud.infini-ai.com/maas/v1/chat/completions'
#url = 'https://api.siliconflow.cn/v1/chat/completions'
# Replace with your own API key
api_key = 'sk-xpodwjxbeihcqhexkitjhfboxqctafgxrshatzxsedgouufu'
prompt = '''
你是一位专业且有帮助的AI助手，专注于理解并调用API工具来解答用户的问题，你的回答需要科学严谨、严格符合输出格式，具体要求如下：

1.**定义：**
    - **api列表的定义：**你会收到一个api列表，里面存有若干可以调用的api，api的'description'字段表示这个api的功能，'parameters'字段'表示调用时应该填入的参数。
    - **user_messages列表的定义：**user_messages列表表示用户提出的若干需求，这些需求可能包含了需要调用的api的参数。

2.**任务内容：**
    -你需要从头开始逐一分析user_messages列表里的每一个元素
    -首先思考用户的需求需要你调用哪几个api
    -然后思考在第几个元素的时候你获得了调用这些api所需的全部参数
    -最后思考用什么样的正确格式填入参数。
    -如果最后你发现这个题目中user没有给出足够调用api的全部参数，那么直接输出bad question

3.**输出格式要求：**
    -你需要输出一个列表，这个列表的长度和user_messages列表相等，表示对于用户的每一句话做出的回应。
    -这个列表的全部元素都是列表，但是只有一个列表是非空列表。
    -这个非空列表出现的位置就是你认为的已经获得足够可以调用若干个api的参数的那句user_messages对应的位置。
    -非空列表中有若干个字典，每个字典的key有两个，分别是"name"表示api名称，以及"arguments"表示api需要填入的参数
    -你可以只调用一个api，或者调用一个api多次，或者调用多个不同的api来回答，但是输出列表只能有一个非空元素表示你回答的那轮对话
    -如果最后你发现这个题目中user没有给出足够调用api的全部参数，那么直接输出字符串bad question

4.**演示示例：**
    -**输入示例：**
{"id": "827", "apis": [{"name": "query_token_balance", "description": "查询指定地址在特定区块链上的代币余额。", "parameters": {"type": "object", "properties": {"product_id": {"type": "string", "description": "钱包的区块链地址"}, "token_contract_address": {"type": "string", "description": "代币的智能合约地址"}, "network": {"type": "string", "description": "区块链网络名称"}, "include_usd_value": {"type": "boolean", "description": "是否包含以美元计算的余额价值", "default": false}, "decimals": {"type": "nteger", "description": "产品是否激活", "default": true}}, "required": ["wallet_address", "token_contract_address", "network"]}}, {"name": "milk_quality_analysis", "description": "分析牛奶的质量，包括成分和卫生指标", "parameters": {"type": "object", "properties": {"fat_content": {"type": "number", "description": "牛奶中的脂肪含量（百分比）"}, "protein_content": {"type": "number", "description": "牛奶中的蛋白质含量（百分比）"}, "lactose_content": {"type": "number", "description": "牛奶中的乳糖含量（百分比）"}, "somatic_cell_count": {"type": "number", "description": "牛奶中的体细胞数（每毫升）"}, "total_bacterial_count": {"type": "number", "description": "牛奶中的总细菌数（每毫升）"}}, "required": ["fat_content", "protein_content", "lactose_content", "somatic_cell_count", "total_bacterial_count"]}}, {"name": "monitor_machine_health", "description": "监控机器设备的健康状态，减少故障和停机时间", "parameters": {"type": "object", "properties": {"machine_id": {"type": "string", "description": "机器设备的唯一标识符"}, "vibration_levels": {"type": "number", "description": "机器运作时的振动幅度"}, "temperature": {"type": "number", "description": "机器运作时的温度"}, "operating_hours": {"type": "number", "description": "机器已连续运行的小时数"}, "include_downtime_analysis": {"type": "boolean", "description": "是否包括停机分析报告"}}, "required": ["machine_id", "vibration_levels", "temperature", "operating_hours", "include_downtime_analysis"]}}], "user_messages": ["你好", "我想查一下钱包地址0x742d35Cc6634C0532925a3b844Bc454e4438f44e在Ethereum网络上，代币合约地址为0x1985365e9f78359a9B6AD760e32412f4a445E862的代币余额，并且需要包含以美元计算的余额价值，代币的小数位数是18。另外，我还想查一下钱包地址bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq在Bitcoin网络上，代币合约地址为0x6B175474E89094C44Da98b954EedeAC495271d0F的代币余额。"]}
    --**输出示例：**
[[],[{"name": "query_token_balance","arguments": {"wallet_address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "token_contract_address": "0x1985365e9f78359a9B6AD760e32412f4a445E862", "network": "Ethereum", "include_usd_value": true, "decimals": 18}}, {"name": "query_token_balance","arguments": {"wallet_address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq", "token_contract_address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "network": "Bitcoin"}}]]

5.**以下是我的正式输入，请开始任务：**
'''
#model = "test"
model = "Qwen2.5-72B"
# 初始化线程安全的文件写入锁
write_lock = threading.Lock()

# 优化HTTP连接池配置
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, 
                status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries, pool_connections=512, pool_maxsize=512))
session.mount('http://', HTTPAdapter(max_retries=retries, pool_connections=512, pool_maxsize=512))

def process_data(current_data):
    """带重试机制的数据处理函数"""
    output = None
    for attempt in range(RETRY_TIMES):
        try:
            output = generate_ans(session, current_data)
            if output:
                return output
        except Timeout:
            if attempt == RETRY_TIMES - 1:
                print(f"数据 {current_data['id']} 请求超时，跳过")
                return None
        except Exception as e:
            print(f"其他错误: {e}")
    return None

def generate_ans(session, text_content):
    """使用连接池的请求函数"""
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }
    
    data = {
        "model": model,
        "messages": [
            {"role": "system", "content": prompt},
            {"role": "user", "content": str(text_content)}
        ],
        "temperature": 0.3
    }
    
    response = session.post(url, headers=headers, json=data, 
                           timeout=TIMEOUT, verify=False)
    response.raise_for_status()
    return response.json()["choices"][0]["message"]['content']

def write_result(output_data, out_file):
    """线程安全的写入函数"""
    json_line = json.dumps(output_data, ensure_ascii=False) + "\n"
    with write_lock:
        out_file.write(json_line)
file_path = "qwen+glm_multi.jsonl"
def main():
    # 初始化数据
    with open(file_path, "r", encoding="utf-8") as f:
        data = [json.loads(line) for line in f]
    
    with (ThreadPoolExecutor(max_workers=CONCURRENCY) as executor,
          open('result_qwen+glm2.jsonl', 'a', encoding='utf-8') as out_file):
        
        # 提交所有任务
        futures = {
            executor.submit(
                process_data, 
                current_data
            ): current_data["id"] 
            for current_data in data
        }
        
        # 处理完成的任务
        for future in as_completed(futures):
            current_id = futures[future]
            try:
                result = future.result()
                if not result:
                    continue
                
                # 结果解析逻辑
                output1, output2 = parse_output(result)
                
                # 获取原始数据
                original_data = next(d for d in data if d["id"] == current_id)
                
                # 构建输出对象
                output_data = {
                    "id": current_id,
                    "targets": output2,
                    "apis": original_data['apis'],
                    "user_messages": original_data['user_messages'],
                    "think": output1
                }
                if "bad question" not in output2:
                # 写入文件
                    write_result(output_data, out_file)
                
            except Exception as e:
                print(f"任务 {current_id} 处理失败: {str(e)}")

def parse_output(output):
    """解析输出结果的公共方法"""
    output1 = []
    output2 = ""
    
    if "</think>" in output:
        parts = output.split("</think>")
        output1 = parts[0]
        output2 = parts[1][1:] if len(parts) > 1 else ""
    
    # 清理代码块标记
    if "```json" in output2:
        output2 = output2.split("```json")[1][1:]
    if "```" in output2:
        output2 = output2.split("```")[0]

    # 替换Python不兼容的语法
    replacements = {
        "true": "True",
        "false": "False",
        "null": "None"
    }
    for k, v in replacements.items():
        output2 = output2.replace(k, v)
    
    try:
        output2 = eval(output2)
    except Exception as e:
        print(f"解析失败: {e}")
        output2 = []
    
    return output1, output2

if __name__ == "__main__":
    main()